﻿using System;
using System.Collections.Specialized;
using System.Data;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;
using Microsoft.ApplicationBlocks.Data;
using visinia.SmartEngine.Providers;
using visinia.SmartEngine.Security;

namespace visinia.SmartEngine.SqlDataProviders.Security
{
    public class visiniaMembershipProvider : MembershipProvider
    {
        #region INIT
        private static string _sqlConnectionString = null;
        public string ConnectionString
        {
            get { return _sqlConnectionString; }
        }
        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            base.Initialize(name, config);
            _sqlConnectionString = ProviderController.GetDataProviderConnectionString();
        }
        #endregion

        #region NOT IMPLEMENTED
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }
        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }
        #endregion

        const string _ApplicationName = "visinia";

        public override string ApplicationName
        {
            get { return _ApplicationName; }
            set { throw new NotImplementedException(); }
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            SqlHelper.ExecuteNonQuery(ConnectionString, "SecurityCreateUser", username, HashPassword(password), email);
            status = MembershipCreateStatus.Success;
            MembershipController.OnUserAdded(username, new EventArgs());
            return FillMembershipUser(username, email);
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            SqlHelper.ExecuteNonQuery(ConnectionString, "SecurityDeleteUser", username);
            MembershipController.OnUserDeleted(username, new EventArgs());
            return true;
        }

        public override bool EnablePasswordReset
        {
            get { return false; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return false; }
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection users = new MembershipUserCollection();
            users = FillMembershipUserCollection(SqlHelper.ExecuteReader(ConnectionString, "SecurityGetAllUsers"));
            totalRecords = users.Count;
            return users;
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            return FillMembershipUser(SqlHelper.ExecuteReader(ConnectionString, "SecurityGetUser", username));
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            return GetUser(providerUserKey.ToString(), userIsOnline);
        }

        public override string GetUserNameByEmail(string email)
        {
            return FillString(SqlHelper.ExecuteReader(ConnectionString, "SecurityGetUserNameByEmail", email));
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return 5; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return 0; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return 4; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return MembershipPasswordFormat.Hashed; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return false; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return false; }
        }

        public override void UpdateUser(MembershipUser user)
        {
            SqlHelper.ExecuteNonQuery(ConnectionString, "SecurityUpdateUser", user.UserName, user.Email);
        }

        public override bool ValidateUser(string username, string password)
        {
            string storedpassword = FillString(SqlHelper.ExecuteReader(ConnectionString, "SecurityValidateUser", username));
            if (!string.IsNullOrEmpty(storedpassword))
            {
                if (storedpassword == HashPassword(password))
                    return true;
            }
            return false;
        }

        #region UTILITY
        public static string HashPassword(string plainMessage)
        {
            byte[] data = Encoding.UTF8.GetBytes(plainMessage);
            using (HashAlgorithm sha = new SHA256Managed())
            {
                byte[] encryptedBytes = sha.TransformFinalBlock(data, 0, data.Length);
                return Convert.ToBase64String(sha.Hash);
            }
        }

        private MembershipUser FillMembershipUser(IDataReader dr)
        {
            while (dr.Read())
            {
                return ActualRead(dr);
            }
            return null;
        }

        private MembershipUserCollection FillMembershipUserCollection(IDataReader dr)
        {
            MembershipUserCollection list = new MembershipUserCollection();
            while (dr.Read())
            {
                list.Add(ActualRead(dr));
            }
            return list;
        }

        private MembershipUser ActualRead(IDataReader dr)
        {
            string username = "";
            string email = "";
            if (dr["Name"] != Convert.DBNull)
                username = ((string)dr["Name"]);
            if (dr["Email"] != Convert.DBNull)
                email = ((string)dr["Email"]);
            return FillMembershipUser(username, email);
        }

        private MembershipUser FillMembershipUser(string userName, string email)
        {
            MembershipUser user = new MembershipUser(
                                    Name, userName, userName, email, String.Empty, String.Empty, true, false, DateTime.Now, DateTime.Now, DateTime.Now,
                                    DateTime.Now, new DateTime(1980, 1, 1));
            return user;
        }
        private string FillString(IDataReader dr)
        {
            string value = "";
            while (dr.Read())
            {
                if (dr[0] != Convert.DBNull)
                    value = ((string)dr[0]);
            }
            return value;
        }
        #endregion
    }
}
